home *** CD-ROM | disk | FTP | other *** search
- ;**************************************************************************;
- ;* S W A P A . A S M *;
- ;*------------------------------------------------------------------------*;
- ;* Task : Assembler module for the SWAP unit *;
- ;*------------------------------------------------------------------------*;
- ;* Author : MICHAEL TISCHER *;
- ;* developed on : 06/01/1989 *;
- ;* last update : 02/28/1990 *;
- ;*------------------------------------------------------------------------*;
- ;* assembly : TASM - /MX SWAPA *;
- ;* ... bind to the SWAP unit *;
- ;**************************************************************************;
-
- ;== Constants ===============================================================
-
- STACK_LEN equ 64 ;Number of words in the internal stack
-
- ;== Structures =============================================================
-
- ExecStruc struc ;Data structure for EXEC function
- EsSegEnv dw ? ;Segment address of environment blocks
- EsCmdPAdr dd ? ;Pointer to command line parameters
- EsFCB1Adr dd ? ;Pointer to FCB #1
- EsFCB2Adr dd ? ;Pointer to FCB #2
-
- ExecStruc ends
-
- public SwapOutAndExec ;Gives a Turbo Pascal program the
- ;ability to pass the address of
- ;the assembler handler
- public InitSwapa ;Initialization procedure
-
- ;== Data segment ===========================================================
-
- DATA segment word public
-
- extrn PrefixSeg : word ;Segment address of PSP in Turbo variables
-
- DATA ends
-
- ;== Program ===============================================================
-
- CODE segment byte public ;Program segment
-
-
- ;== Variables in code segment ===============================================
-
- CodeStart equ this word ;Code begins here which is copied to
- ;the Turbo program
-
- ;-- Variables needed by the Swap routines for uploading and downloading ----
-
- CoStAddr dd ? ;Orig. address of PARA(CodeStart)
- CoStLen dw ? ;Number of words swapped w/ CoStAddr
- StackPtr dw ? ;Gets old stack pointer
- StackSeg dw ? ;Gets old stack segment
- TurboSeg dw ? ;Segment address - Turbo code segment
-
- ;-- Variables needed for program configuration and command execution -------
-
- NewStack dw STACK_LEN dup (?) ;New stack
- EndStack equ this word ;End of stack
-
- Command dd ? ;Pointer to command
- CmdPara dd ? ;Pointer to command line parameters
- ToDisk db ? ;True when disk swapping occurs
- Handle dw ? ;Disk or EMS handle
- Len dd ? ;Number of bytes saved
-
- FCB1 db 16 dup ( 0 ) ;FCB #1 for PSP
- FCB2 db 16 dup ( 0 ) ;FCB #2 for PSP
- CmdBuf db 128 dup ( 0 ) ;Commands following prg. name
- PrgName db 64 dup ( 0 ) ;Program name
- ExecData ExecStruc < 0, CmdBuf, FCB1, FCB2 > ;Data structure for EXEC
-
- OldPara dw ? ;Number of previously reserved paragraphs
- FrameSeg dw ? ;Segment address of EMS page frame
- Error_Code db 0 ;Error code for caller
-
- TerMes db 13,10,13,10
- db "╔═══════════════════════════════════════════════════╗",13,10
- db "║ Done_Swap: Stored Turbo Pascal program could ║",13,10
- db "║ not be reloaded back into memory. ║",13,10
- db "║ Program execution terminated! ║",13,10
- db "╚═══════════════════════════════════════════════════╝"
- db 13,10,13,10,"$"
-
- Msg1 db 13,10,13,10
- db "╔════════════════════════════╗",13,10
- db "║ Init_Swap: Swapping out ║",13,10
- db "╚════════════════════════════╝"
- db 13,10,13,10,"$"
-
-
- ;== Procedures =============================================================
-
- ;---------------------------------------------------------------------------
- ;-- StartSwap : Coordinate swapping of Turbo Pascal program
-
- StartSwap proc far
-
- assume cs:code, ds:nothing
-
- ;-- Store current stack and initialize new stack ----------------
-
- cli ;Suppress interrupts
- mov StackPtr,sp ;Mark current stack
- mov StackSeg,ss
- push cs ;Install new stack
- pop ss
- mov sp,offset EndStack - 2
- sti ;Re-enable interrupts
-
- push cs ;Set DS to CS
- pop ds
- assume cs:code, ds:code
-
- ;-- Overwrite unnecessary memory --------------------------------
-
- cmp ToDisk,0 ;Write to EMS memory?
- je Ems ;Yes ---> Ems
-
- call Write2File ;No ---> Write to file
- jnc ShrinkMem ;No error ---> ShrinkMem
-
- mov Error_Code, 1 ;File output error?
- jmp short GetBack ;return to Turbo
-
- Ems: mov ah,41h ;Pass segment address of the page frame
- int 67h ;Call EMM
- mov FrameSeg,bx ;Place result in variables
-
- call Write2Ems ;Write program to EMS
-
- ;-- Provide number of currently allocated paragraphs ------------
-
- ShrinkMem: mov ax,TurboSeg ;Segment address of Turbo code segment
- sub ax,11h ;Allocate 10 paragraphs for PSP and 1
- ;for MCB
- mov es,ax ;ES now pointer to Turbo prog. MCB
- mov bx,es:[3] ;Get number of paragraphs allocated
- mov OldPara,bx ;and place in variable
-
- ;-- Calculate the number of paragraphs needed and reduce --
- ;-- memory requirements by this amount --
-
- inc ax ;AX now points to the PSP
- mov es,ax ;for function call to ES
- mov bx,CostLen ;Number of words needed by Swap routine
- add bx,128+7 ;Recalculate and round off PSP
- mov cl,3 ;Divide by 8 words (per paragraph)
- shr bx,cl
-
- mov ah,4Ah ;Function number for "change size"
- int 21h ;Call DOS interrupt
-
- ;-- Execute specified command line using the EXE function ------
-
- mov bp,ds ;Store DS
-
- mov ax,cs ;Set ES and DS to CS
- mov es,ax
- mov ds,ax
-
- ;-- Enter segment address of code segments in the pointer -----
- ;-- to the EXEC structure
-
- mov word ptr ExecData.EsFCB1Adr + 2,ax
- mov word ptr ExecData.EsFCB1Adr + 2,ax
- mov word ptr ExecData.EsCmdPAdr + 2,ax
-
- mov bx,offset ExecData ;ES:BX point to parameter block
- mov dx,offset PrgName ;DS:DX point to command string
-
- mov ax,4B00h ;Function number for "EXEC"
- int 21h ;Call DOS interrupt
- mov ds,bp ;Move DS
- jnc ReMem ;No error ---> ReMem
-
- mov Error_Code,ah ;Note ErrorCode
-
- ;-- Return memory to original size ------------------------------
-
- ReMem: mov ax,TurboSeg ;Set Turbo code segment address
- sub ax,10h ;to start of PSP
- mov es,ax ;and load into ES
- mov bx,OldPara ;Old number of paragraphs
-
- mov ah,4Ah ;Function number for "change size"
- int 21h ;Call DOS interrupt
- jnc GetBack ;No error ---> GetBack
-
- jmp Terminate ;Error in ReMem --> End program
-
- ;-- Return to program -------------------------------------------
-
- GetBack: cmp ToDisk,0 ;Write to EMS memory?
- je Ems1 ;Yes ---> Ems1
-
- call GetFromFile ;No, reload as file
- jnc CloseUp ;No error ---> CloseUp
-
- jmp Terminate ;Read error, end program
-
- Ems1: call GetFromEms ;Get Turbp Pascal program from EMS memory
-
- ;-- Restore old stack -------------------------------------------
-
- CloseUp: cli ;Suppress interrupts
- mov ss,StackSeg
- mov sp,StackPtr
- sti ;Re-enable interrupts
-
- ;-- Prepare registers for swap ----------------------------------
-
- push cs ;Push DS to CS
- pop ds
- assume cs:code, ds:code
-
- mov cx,CoStLen ;Number of words to be swapped
- mov di,cx ;Move number of words to DI
- dec di ;Decrement by one word
- shl di,1 ;Double it
- mov si,di ;move to SI
- add di,word ptr CostAddr ;DI+offset addr. of Swap routine
- mov es,word ptr CostAddr + 2 ;ES gets old CS of Swap routine
- mov ds,TurboSeg ;Seg addr. of start of code
-
- ret ;Return to SwapOutAndExec
-
- StartSwap endp
-
- ;---------------------------------------------------------------------------
- ;-- Write2Ems : Write program to be swapped to EMS memory
- ;-- Input : BX = Segment address of EMS page frame
- ;-- DS = Codesegment
-
- EMS_PLEN equ 16384 ;Length of an EMS page
-
- HiWLen dw ? ;Remaining Hi-Word length
-
- Write2Ems proc near
-
- push ds ;Push DS onto stack
- cld ;Increment on string instructions
- mov es,bx ;ES points to the page frame
-
- mov bp,word ptr Len ;Move Lo-Word length to BP
- mov ax,word ptr Len + 2 ;Move Hi-Word length to AX
- mov HiWLen,ax ;and then to variable
-
- mov dx,Handle ;Move EMS Handle to DX
- xor bx,bx ;Start with first logical page
-
- assume cs:code, ds:nothing
-
- jmp short WriECalc ;Jump in the loop
-
- WriELoop: ;-- Register allocation within this loop -----------------------
- ;
- ; AX = Times this, times that
- ; BX = Number of logical EMS pages to be addressed
- ; CX = Number of bytes to be copied in this execution
- ; DX = EMS handle
- ; ES:DI = Pointer to first page in EMS page frame (Target)
- ; DS:SI = Pointer to first word to be copied (Start)
- ; HiWLen:BP = Number of bytes remaining to be copied
-
- mov ax,4400h ;Function number for illustration
- int 67h ;Call EMM
-
- mov si,offset CodeEnd ;Offset for Swapping
- xor di,di ;Write to the start of the EMS page
- mov ax,cx ;Move number to AX
- rep movsb ;Copy memory
-
- sub bp,ax ;Remainder of written bytes
- sbb HiWLen,0 ;Decrement
-
- inc bx ;Increment number of logical page
-
- mov ax,ds ;Starting segment to AX
- add ax,EMS_PLEN shr 4 ;Increment by written paragraphs
- mov ds,ax ;and move to DS
-
- WriECalc: mov cx,EMS_PLEN ;Write EMS_PLEN bytes
- cmp HiWLen,0 ;More than 64K?
- ja WriELoop ;Yes ---> WriELoop
- cmp bp,cx ;No ---> More than EMS_PLEN bytes?
- jae WriELoop ;Yes ---> Continue writing
- mov cx,bp ;No ---> Write remainder
- or cx,cx ;No more bytes to write?
- jne WriELoop ;No ---> WriELoop
-
- WriERet: pop ds ;Pop DS off of stack
- ret ;Return to caller
-
- Write2Ems endp
-
- ;---------------------------------------------------------------------------
- ;-- GetFromEms : Get the swapped program from EMS memory
- ;-- Input : DS = Code segment
-
- GetFromEms proc near
-
- push ds ;Push DS onto the stack
- cld ;Increment on string instructions
-
- mov bp,word ptr Len ;Move Lo-Word length to BP
- mov ax,word ptr Len + 2 ;Move Hi-Word length to AX
- mov HiWLen,ax ;and from there to variable
-
- mov dx,Handle ;Move EMS handle to DX
- xor bx,bx ;Start with first logical page
-
- mov ds,FrameSeg ;DS points to the page frame
- push cs ;Set ES to the code segment
- pop es
-
- assume cs:code, ds:nothing
-
- jmp short GetECalc ;Jump to the loop
-
- GetELoop: ;-- Register allocation within this loop -----------------------
- ;
- ; AX = times this, times that
- ; BX = Number of logical EMS pages to be swapped
- ; CX = Number of bytes to be copied in this execution
- ; DX = EMS handle
- ; DS:SI = Pointer to first page in EMS page frame (Start)
- ; ES:DI = Pointer to target address in memory
- ; HiWLen:BP = Number of bytes still to be copied
-
- mov ax,4400h ;Function number for illustration
- int 67h ;Call EMM
-
- mov di,offset CodeEnd ;Offset for Swapping
- xor si,si ;Write to the start of the EMS page
- mov ax,cx ;Move number to AX
- rep movsb ;Copy memory
-
- sub bp,ax ;Remainder of written bytes
- sbb HiWLen,0 ;Decrement
-
- inc bx ;Increment number of logical page
-
- mov ax,es ;Move starting segment to AX
- add ax,EMS_PLEN shr 4 ;Increment by written paragraphs
- mov es,ax ;and move it to ES
-
- GetECalc: mov cx,EMS_PLEN ;Write EMS_PLEN bytes
- cmp HiWLen,0 ;More than 64K?
- ja GetELoop ;Yes ---> GetELoop
- cmp bp,cx ;No ---> More than EMS_PLEN bytes?
- jae GetELoop ;Yes ---> Continue writing
- mov cx,bp ;No ---> Write remainder
- or cx,cx ;No more bytes to write?
- jne GetELoop ;No ---> GetELoop
-
- GetERet: pop ds ;Pop DS off of stack
- ret ;Return to caller
-
- GetFromEms endp
-
- ;---------------------------------------------------------------------------
- ;-- Write2File : Write the program to be swapped to a file
- ;-- Returns : Carry-Flag = 1 : Error
-
- Write2File proc near
-
- NUM_WRITE = 2048 ;Bytes to be written per execution
- ;to power of 2 (max. 2^16)
- assume cs:code, ds:code
-
- push ds ;Push DS onto stack
- mov bp,4000h ;Function number for "Write"
- mov bx,Handle ;Load file handle
-
- WriFStart: mov di,word ptr Len ;Move Lo-Word length to DI
- mov si,word ptr Len + 2 ;Move Hi-Word length to SI
- mov dx,offset CodeEnd ;Write offset address
- jmp short WriFCalc ;Compute no. of bytes to be written
-
- WriFLoop: ;-- Register allocation within this loop -----------------
- ;
- ; AX = times this, times that
- ; BX = DOS file handle
- ; CX = Number of bytes to be read/written
- ; DS:DX = Address at which they should be read/written
- ; DI:SI = Number of bytes still to be copied
- ; BP = Number of DOS funtion to be called
-
- mov ax,bp ;Load DOS function number
- int 21h ;Call DOS interrupt
- jc WriFEnd ;Error ---> WriFEnd
- mov ax,ds ;Starting segment to AX
- add ax,NUM_WRITE shr 4 ;Increment by written paragraphs
- mov ds,ax ;and move to DS
- sub di,cx ;Decrement remainder of
- sbb si,0 ;written bytes
-
- WriFCalc: mov cx,NUM_WRITE ;Write NUM_WRITE bytes
- cmp si,0 ;More than 64K?
- ja WriFLoop ;Yes ---> WriFLoop
- cmp di,cx ;No ---> More than NUM_WRITE bytes?
- jae WriFLoop ;Yes ---> Continue writing
- mov cx,di ;No ---> Write remainder
- or cx,cx ;No more bytes to write?
- jne WriFLoop ;No ---> WriFLoop
-
- WriFEnd: pop ds ;Reload DS
- WriFRet: ret ;Return to caller
-
- Write2File endp
-
- ;---------------------------------------------------------------------------
- ;-- GetFromFile : Return the swapped program to memory
- ;-- Returns : Carry-Flag = 1 : Error
-
- GetFromFile proc near
-
- assume cs:code, ds:code
-
- push ds ;Push DS onto the stack
-
- ;-- Move file pointer to the start of file ----------------
-
- mov ax,4200h ;DOS function number
- mov bx,Handle ;Load file handle
- xor cx,cx ;CX:DX gives its position
- mov dx,cx
- int 21h ;Call DOS interrupt
- jc WriFRet ;Error ---> WriFRet
-
- ;-- Load file into memory with the help of Write2File -----
-
- mov bp,3F00h ;Function number for "Read"
- jmp WriFStart ;Jump to Write2File
-
- GetFromFile endp
-
- ;---------------------------------------------------------------------------
- ;-- Terminate : The system can't return to the original Turbo Pascal
- ;-- program. The program ends with an error code.
-
- Terminate label near
-
- ;-- Display error message ---------------------------------------
-
- push cs ;Set DS to CS
- pop ds
- mov dx,offset TerMes ;DS:DX points to the error message
- mov ah,9 ;Function number for "Display string"
- int 21h ;Display DOS interrupt
-
- mov ax,4C01h ;End program with error code
- int 21h
-
-
- ;===========================================================================
-
- CodeEnd equ this byte ;Copy code from the start of the Turbo
- ;Pascal program to this point
-
- ;---------------------------------------------------------------------------
- ;-- SwapOutAndExec : Swaps the current program to EMS memory or hard disk
- ;-- and starts another program using the DOS EXEC function
- ;-- Call from Turbo: SwapOutAndExec( Command,
- ;-- CmdPara : string;
- ;-- ToDisk : boolean;
- ;-- Handle : word;
- ;-- Len : longint );
- ;-- Info : The Command and CmdPara parameters must be configured
- ;-- as strings in DOS format.
-
- SwapOutAndExec proc near
-
- ACommand equ dword ptr [bp+16] ;Constants for accessing the
- ACmdPara equ dword ptr [bp+12] ;specified arguments
- AToDisk equ byte ptr [bp+10]
- AHandle equ word ptr [bp+ 8]
- ALen equ dword ptr [bp+ 4]
- ARG_LEN equ 16 ;Lengths of arguments
-
- assume cs:code, ds:data
-
- push bp ;Enable access to the arguments
- mov bp,sp
-
- ;-- Copy program name to buffer in code segment -----------------
-
- push ds
- push ax
- push dx
- push cs
- pop ds
- mov ah,9
- mov dx,offset Msg1
- int 21h
- pop dx
- pop ax
- pop ds
-
- mov dx,ds ;Mark DS
- push cs ;Set ES to CS
- pop es
-
- lds si,ACommand ;DS:SI points to command buffer
- mov di,offset PrgName ;ES:DI points to PrgName
- cld ;Increment on string instructions
- lodsb ;Read length of Pascal string
- cmp al,64 ;More than 64 characters?
- jbe CmdCopy ;No ---> CmdCopy
-
- mov al,64 ;Yes ---> Copy a maximum of 64 characters
-
- CmdCopy: xor ah,ah ;Set Hi-Byte to 0 length and
- mov cx,ax ;load into the counter
- rep movsb ;Copy string
-
- ;-- Copy command line in buffer in code segment -----------------
-
- lds si,ACmdPara ;DS:SI points to CmdPara buffer
- mov di,offset CmdBuf ;ES:DI points to CmdBuf
- lodsb ;Read length of Pascal string
- cmp al,126 ;More than 126 characters?
- jbe ParaCopy ;No ---> ParaCopy
-
- mov al,126 ;Yes ---> Copy maximum of 126 characters
-
- ParaCopy: stosb ;Store length as first byte
- xor ah,ah ;Set Hi-Byte to 0 length and
- mov cx,ax ;load into the counter
- rep movsb ;Copy string
-
- mov al,0dH ;Add carriage return
- stosb
-
- ;-- Transfer filename from command line to FCBs -----------------
-
- push cs ;Transfer CS to DS
- pop ds
-
- mov si,offset CmdBuf+1 ;DS:SI points to CmdBuf + 1
- mov di,offset FCB1 ;ES:DI points to FCB #1
- mov ax,2901h ;Function no.:"Transfer filename to FCB"
- int 21h ;Call DOS interrupt
-
- mov di,offset FCB2 ;ES:DI now points to FCB #2
- mov ax,2901h ;Function no.: "Transfer filename to FCB"
- int 21h ;Call DOS interrupt
-
- mov ds,dx ;Move old value into DS
-
- ;-- Transfer remaining parameters to variables ------------------
-
- les ax,ALen ;Change length
- mov word ptr Len + 2,es
- mov word ptr Len,ax
-
- mov al,AToDisk ;Change disk flag
- mov ToDisk,al
-
- mov ax,AHandle ;Change handle
- mov Handle,ax
-
- push ds ;Push DS onto the stack
-
- ;-- Exchange variables and program code between labels CodeStart -
- ;-- and CodeEnd with the contents of the PSP code segment
-
- mov ax,PrefixSeg ;ES:DI points to start of Turbo
- add ax,10h ;program following PSP
- mov TurboSeg,ax ;Mark addr. of Turbo code segment
- mov es,ax
- xor di,di
-
- push cs ;Set DS to CS
- pop ds
- assume cs:code, ds:code
-
- mov si,offset CodeStart ;DS:SI points to CodeStart
- and si,0FFF0h ;Round off at start of paragraph
-
- mov cx,CostLen ;Get number of words to be swapped
- mov word ptr CoStAddr,si ;Mark address of
- mov word ptr CoStAddr + 2,ds ;PARA(Codestart)
-
- mov dx,es ;Mark target segment in DX
- cld ;Increment on SI/DI string instructions
-
- ;-- Swap loop ---------------------------------------------------
-
- dl_loop: mov ax,[si] ;Load word from assembler module
- mov bx,es:[di] ;Load word from Turbo Pascal program
- stosw ;Write assm. module word to Turbo program
- mov [si],bx ;Write Turbo program word to assm. module
- inc si ;Set SI to next word
- inc si ;(increment SI through STOSW)
- loop dl_loop ;Use all words
-
- ;-- Adapt segment address of code segment before calling the ---
- ;-- StartSwap procedure so that variable references to the code
- ;-- segment remain unchanged
-
- mov ax,offset CodeStart ;Compute number of paragraphs between
- mov cl,4 ;CodeStart and the start of the
- shr ax,cl ;segment, and get segment address in
- sub dx,ax ;DX
-
-
- push cs ;Return address to BACK label
- mov ax,offset back ;Move onto the stack
- push ax
-
- push dx ;Push segment address onto stack
- mov ax,offset StartSwap ;Move offset address onto stack
- push ax
-
- retf ;FAR-RET to StartSwap
-
- Msg2 db 13,10,13,10
- db "╔════════════════════════════╗",13,10
- db "║ Done_Swap: Swapping in ║",13,10
- db "╚════════════════════════════╝"
- db 13,10,13,10,"$"
-
- back: ;----------------------------------------------------------------
- ;-- Returns original program to main memory and executes the
- ;-- program.
- ;-- Registers have the following contents:
- ;-- DS:SI = End of assembler code following the PSP
- ;-- ES:DI = End of Turbo code in the SWAP unit
- ;-- CX = Number of words
- ;----------------------------------------------------------------
-
- assume cs:code, ds:nothing
-
- std ;Decrement string instructions by SI/DI
-
- ;-- Swap back loop ----------------------------------------------
-
- push ds
- push ax
- push dx
- push cs
- pop ds
- mov ah,9
- mov dx,offset Msg2
- int 21h
- pop dx
- pop ax
- pop ds
-
- ul_loop: mov bx,es:[di] ;Get byte from old memory range
- mov ax,[si] ;Get byte from current memory range
- mov [si],bx ;Byte from old memory rng to current rng
- dec si ;Set SI to previous word
- dec si
- stosw ;Byte from current memory rng to old rng
- loop ul_loop ;Repeat until memory ranges are exchanged
-
- pop ds ;Pop DS off of stack
- assume ds:data
-
- pop bp ;Pop BP
-
- ;-- MOV SP,BP must not be given, since SP doesn't change
-
- xor ah,ah ;Place error code in AX
- mov al,Error_Code
-
- ret ARG_LEN ;Return to caller, clear arguments
- ;from stack
-
- SwapOutAndExec endp
-
-
- ;---------------------------------------------------------------------------
- ;-- InitSwapa : Computes the number of bytes/words allocated for a program
- ;-- swap with the start of the Turbo program in memory
- ;-- Input : none
- ;-- Output : number of bytes
- ;-- Pascal call : function InitSWapa : word;
- ;-- Info : This procedure must be called before the
- ;-- first call to SwapOutAndExec!
-
- InitSwapa proc near
-
- assume cs:code, ds:data
-
- mov bx,offset CodeStart ;AX points to start of code
- and bx,0FFF0h ;Round off at start of paragraph
- mov ax,offset CodeEnd ;BX points to end of code
- sub ax,bx ;Compute number of bytes
- inc ax ;Convert CX to words
- shr ax,1
- mov CoStLen,ax ;Mark number of words to be swapped
- shl ax,1 ;Convert to bytes
-
- ;-- Return contents of AX as function result
-
- ret ;Return to caller
-
- InitSwapa endp
-
- ;---------------------------------------------------------------------------
-
- CODE ends ;End of code segment
- end ;End of program
-